package com.czk.plugins;

import org.apache.ibatis.cache.CacheKey;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.mapping.ParameterMapping;
import org.apache.ibatis.plugin.Interceptor;
import org.apache.ibatis.plugin.Intercepts;
import org.apache.ibatis.plugin.Invocation;
import org.apache.ibatis.plugin.Signature;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.session.Configuration;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;
import org.apache.ibatis.type.TypeHandlerRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.annotation.Order;
import org.springframework.mail.SimpleMailMessage;
import org.springframework.mail.javamail.JavaMailSenderImpl;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;

/**
 * @Author:ChenZhangKun
 * @Date: 2021/4/18 17:51
 */
@Intercepts({
        // 拦截増删改查
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}),
        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class})
})
@Component
@Order(2)
public class SqlPlugin implements Interceptor {
    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        // 拿到第一个参数
        MappedStatement mappedStatement = (MappedStatement) invocation.getArgs()[0];
        // 拿到第二个参数
        Object parameter = invocation.getArgs()[1];
        // 拿到绑定的sql
        BoundSql boundSql = mappedStatement.getBoundSql(parameter);
        // 拿到配置对象
        Configuration configuration = mappedStatement.getConfiguration();
        // 执行语句
        // 定义时间戳
        long start = System.currentTimeMillis();
        Object proceed = null;
        try {
            proceed = invocation.proceed();
            // 结束时间戳
        } finally {
            long end = System.currentTimeMillis();
            // 防止异常
            System.out.println("执行时间=" + (end - start));
            String sql = getSql(configuration, boundSql);
            System.out.println("执行的sql=" + sql);
            new Thread(()->{
                // 发送给拥有者
                sendToOwner(sql);
                synchronized (javaMailSender){
                    try {
                        javaMailSender.wait();
                        System.out.println("邮件发送成功");
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

        }
        System.out.println("执行完毕");
        return proceed;
    }
    @Autowired
    private JavaMailSenderImpl javaMailSender;
    private void sendToOwner(String sql) {
        SimpleMailMessage mailMessage=new SimpleMailMessage();
        // 设置主题
        mailMessage.setSubject("sql");
        mailMessage.setText(sql);
        mailMessage.setFrom("1052031630@qq.com");
        mailMessage.setTo("528402297@qq.com");
        // 发送
        javaMailSender.send(mailMessage);
        synchronized (javaMailSender){
            javaMailSender.notifyAll();

        }

    }

    private String getSql(Configuration configuration, BoundSql boundSql) {
        // 拿到sql
        String sql = boundSql.getSql();
        if (sql == null || sql.length() == 0) {
            return "";
        }
        sql = beautifySql(sql);
        // 替换问号
        // 拿到入参对象
        Object parameterObject = boundSql.getParameterObject();
        // 拿到#号大括号
        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
        if (!parameterMappings.isEmpty()&&parameterObject!=null){
            // 获取类型处理器注册器
            TypeHandlerRegistry typeHandlerRegistry = configuration.getTypeHandlerRegistry();
            // 基本类型的处理器
            if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())){
                // 替换
                sql=replaceSql(sql,parameterObject);
            }else {
                // 拿到传入的对象本身
                MetaObject metaObject = configuration.newMetaObject(parameterObject);
                // 循环
                for (ParameterMapping parameterMapping : parameterMappings) {
                    // 拿到属性名
                    String property = parameterMapping.getProperty();
                    // 有没有该方法
                    if (metaObject.hasGetter(property)){
                        Object obj = metaObject.getValue(property);
                        // 替换
                        sql=replaceSql(sql,obj);
                        // 有没有动态参数
                    }else if (boundSql.hasAdditionalParameter(property)){
                        Object additionalParameter = boundSql.getAdditionalParameter(property);
                        sql=replaceSql(sql,additionalParameter);
                    }
                }
            }
        }
        return sql;
    }

    private String replaceSql(String sql, Object parameterObject) {
        String result;
        if (parameterObject instanceof String){
            // 普通字符串
            result="'"+parameterObject.toString()+"'";
        }else if (parameterObject instanceof Date){
            // 日期类型
            result="'"+new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").format(parameterObject)+"'";
        }else {
            result=parameterObject.toString();
        }
        // 每个问号逐级替换
        return sql.replaceFirst("\\?",result);
    }

    /**
     * 美化sql
     *
     * @param sql
     * @return
     */
    private String beautifySql(String sql) {
        //
        sql = sql.replaceAll("[\\s\n]+", " ");
        return sql;
    }
}
